package com.zondy.mapgis.map.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Parcel;
import android.os.Parcelable;

import com.zondy.mapgis.android.map.dao.IBaseLayer;
import com.zondy.mapgis.android.utils.StringUtils;
import com.zondy.mapgis.core.attr.FieldType;
import com.zondy.mapgis.core.featureservice.FeatureQuery;
import com.zondy.mapgis.core.geometry.Dot;

/**
 * @content 查询条件，内含属性查询条件和空间查询条件
 * @author admin 2016-8-2 下午2:26:24
 */
public class QueryCondition implements Serializable,Parcelable{

	private static final long serialVersionUID = 1L;
	public static final int QUERYSRC_ARCGIS = 0;
	public static final int QUERYSRC_MAPGIS = 1;

	private String name;
	private IBaseLayer layer;
	private final List<String> fldValues;
	private final QueryModel qm;
	private boolean returnGeom = true;
	private boolean returnAtt = true;

	/**
	 * 空间查询范围名称：全图/屏幕/空间范围/未知
	 */
	private EnumRectName rectName;
	private final DRect rect;
	private int spatialRelaType = FeatureQuery.SPATIAL_REL_OVERLAP;

	/**
	 * 查询语句
	 */
	private String strWhere;
	private Dot[] dots = null;


	public QueryCondition() {
		name = "";
		qm = new QueryModel();
		fldValues = new ArrayList<String>();
		rect = new DRect();
		rectName = EnumRectName.MAP;
	}

	/**
	 * 取查询图层
	 * @return
	 */
	public IBaseLayer getLayer() {
		return layer;
	}

	/**
	 * 设置查询图层
	 * @param layer
	 */
	public void setLayer(IBaseLayer layer) {
		this.layer = layer;
		if (this.layer != null) {
			qm.setLayer(layer.getName());
		}
	}

	/**
	 * 查询模版的图层名称
	 * @return
	 */
	public String getQueryModelLayerName() {
		return qm.getLayer();
	}

	/**
	 * 添加属性查询条件
	 * @param fldName 字段名
	 * @param fldValue 字段值
	 * @param fldType 字段类型
	 * @return
	 */
	public QueryCondition add(String fldName, String fldRelation, String fldValue, FieldType fldType) {
		qm.add(fldName, fldRelation, fldType);
		fldValues.add(fldValue);
		return this;
	}
	/**
	 * 添加属性查询条件
	 * @param fldName 字段名
	 * @param fldValue 字段值
	 * @param fldType 字段类型
	 * @return
	 */
	public QueryCondition add(String fldName, String fldRelation, String fldValue, LandFieldType fldType) {
		qm.add(fldName, fldRelation, fldType);
		fldValues.add(fldValue);
		return this;
	}

	/**
	 * 添加空间查询条件，如果已有空间查询条件，则覆盖之前的。
	 * @param rect
	 * @param rectName 空间范围名称
	 * @return
	 */
	public QueryCondition add(DRect rect, EnumRectName rectName) {

		if (rect == null || rect.isOriginal() || rectName == null) {
			return this;
		}

		this.rect.setXmax(rect.xmax);
		this.rect.setXmin(rect.xmin);
		this.rect.setYmax(rect.ymax);
		this.rect.setYmin(rect.ymin);
		this.rectName = rectName;

		return this;
	}

	/**
	 * 移除一个条件，如果查询条件中没有指定字段，则无操作。
	 * @param fldName 查询字段名
	 * @return 移除后的查询条件字段数
	 */
	public int del(String fldName) {

		int index = StringUtils.getIndex(qm.getFldNames(), fldName);
		if (index >= 0) {
			qm.del(fldName);
			fldValues.remove(index);
		}
		return qm.getFldNames().size();
	}

	/**
	 * 查询条件数
	 * @return
	 */
	public int size() {
		return fldValues.size();
	}

	/**
	 * 移除所有查询字段
	 */
	public void clearFields() {
		qm.clear();
		fldValues.clear();
	}

	/**
	 * 清除查询范围信息
	 */
	public void clearRect() {

		rect.setXmax(0);
		rect.setXmin(0);
		rect.setYmax(0);
		rect.setYmin(0);
		rectName = EnumRectName.MAP;
	}

	/**
	 * 取查询条件中第{@code index}个字段名
	 * @param index
	 * @return
	 */
	public String getFldName(int index) {
		return qm.getFldNames().get(index);
	}

	/**
	 * 取查询条件中第{@code index}个字段值
	 * @param index
	 * @return
	 */
	public String getFldValue(int index) {
		return fldValues.get(index);
	}

	/**
	 * 取查询条件中第{@code index}个字段类型
	 * @param index
	 * @return
	 */
	public LandFieldType getFldType(int index) {
		return qm.getFldTypes().get(index);
	}

	/**
	 * 取查询条件中第{@code index}个字段关系
	 * @param index
	 * @return
	 */
	public String getFldRelation(int index) {
		return qm.getFldRelations().get(index);
	}

	/**
	 * 设置空间查询关系
	 * @param spatialRelaType
	 */
	public void setSpatialRelaType(int  spatialRelaType) {
		this.spatialRelaType = spatialRelaType;
	}

	/**
	 * 取空间查询关系
	 * @return
	 */
	public int  getSpatialRelaType() {
		return spatialRelaType;
	}

	/**
	 * 查询条件字段数
	 * @return 查询条件字段数
	 */
	public int fldsize() {
		return qm.getFldNames().size();
	}

	/**
	 * 查询条件是否合法。<br>
	 * 主要检查以下几项：<br>
	 * 1，查询图层是否存在并且是矢量图层；<br>
	 * 2，查询的字段名称、字段值、字段类型各列表是否大小一致；<br>
	 * 3，是否有空间查询条件。
	 * @return
	 */
	public boolean isLegal() {

		if (layer == null || !layer.isVectorLayer()) {
			return false;
		}
		if (qm.isLegal() && qm.size() == fldValues.size()) {
			List<LandFieldType> qcTypes = qm.getFldTypes();
			for (int ii = 0; ii < qcTypes.size(); ii++) {
				if (qcTypes.get(ii) != LandFieldType.fldString
						&& (fldValues.get(ii) == null || fldValues.get(ii).length() == 0)) {
					return false;
				}
			}
			return true;
		}
		if (!rect.isOriginal()) {
			return true;
		}
		return false;
	}

	/**
	 * 获取查询条件类型
	 * @return
	 */
	public EnumQueryType getQueryType() {

		boolean hasAtt = layer != null
					&& ((layer.isVectorLayer() && qm.isLegal() && qm.size() == fldValues.size()) || !StringUtils
								.isNullOrZero(strWhere));
		boolean hasSpace = rect != null && !rect.isOriginal() && rectName == EnumRectName.SCREEN;

		if (hasAtt && hasSpace) {
			return EnumQueryType.MixQuery;
		} else if (hasAtt) {
			return EnumQueryType.AttQuery;
		} else if (hasSpace) {
			return EnumQueryType.SpaceQuery;
		}
		return EnumQueryType.UnKnown;
	}

	/**
	 * 取空间查询范围
	 * @return
	 */
	public DRect getRect() {
		return rect;
	}

	/**
	 * 取空间查询范围的名称
	 * @return
	 */
	public EnumRectName getRectName() {

		if (layer != null && layer.isVectorLayer() && rect != null && !rect.isOriginal()) {
			DRect rectLayer = layer.getRange();
			if (rect.xmax - rectLayer.xmax >= 0.001 && rect.ymax - rectLayer.ymax >= 0.001
						&& rectLayer.xmin >= 0.001 && rectLayer.ymin >= 0.001) {
				clearRect();
			}
		}

		return rectName;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * 设置查询条件名称，禁止设置空值。
	 * @param name the name to set，如果值为null，则该方法无效
	 */
	public void setName(String name) {
		if (name == null) {
			return;
		}
		this.name = name;
	}

	/**
	 * @return the strWhere
	 */
	public String getStrWhere() {
		return strWhere;
	}

	/**
	 * @param strWhere the strWhere to set
	 */
	public void setStrWhere(String strWhere) {
		this.strWhere = strWhere;
	}

	/**
	 * @return the bReturnGeom
	 */
	public boolean isReturnGeom() {
		return returnGeom;
	}

	/**
	 * @param returnGeom the bReturnGeom to set
	 */
	public void setReturnGeom(boolean returnGeom) {
		this.returnGeom = returnGeom;
	}

	/**
	 * @return the bReturnAtt
	 */
	public boolean isReturnAtt() {
		return returnAtt;
	}

	/**
	 * @param returnAtt the bReturnAtt to set
	 */
	public void setReturnAtt(boolean returnAtt) {
		this.returnAtt = returnAtt;
	}

	/**
	 * 查询类型，由查询图层类型判断是 {@link #QUERYSRC_ARCGIS} 还是 {@link #QUERYSRC_MAPGIS}
	 * @return
	 */
	public int getQuerySrc(){
		if(layer == null){
			return -1;
		}
		if(layer instanceof Layer){
			return QUERYSRC_MAPGIS;
		}
//		else if(layer instanceof ArcLayer){
//			return QUERYSRC_ARCGIS;
//		}
		return -1;
	}
	
	public Dot[] getDots()
	{
		return dots;
	}

	public void setDots(Dot[] dots)
	{
		this.dots = dots;
	}
	/**
	 * 深拷贝一份
	 * @return
	 */
	public QueryCondition copyObj() {

		QueryCondition qc = new QueryCondition();
		if (layer != null) {
			qc.setLayer(layer);
		}
		qc.setName(new String(name));
		qc.setReturnAtt(returnAtt);
		qc.setReturnGeom(returnGeom);

		int fldCount = qm.size();
		for (int index = 0; index < fldCount; index++) {
			qc.add(new String(qm.getFldNames().get(index)),
						new String(qm.getFldRelations().get(index)),
						new String(fldValues.get(index)), qm.getFldTypes().get(index));
		}
		qc.qm.setLayer(qm.getLayer());
		qc.add(new DRect(rect.toString()), EnumRectName.fromString(rectName.getString()));
		return qc;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "QueryCondition [name=" + name + ", layer=" + layer + ", fldValues=" + fldValues
					+ ", qm=" + qm + ", rectName=" + rectName + ", rect=" + rect
					+ ", spatialRelaType=" + spatialRelaType + ", strWhere=" + strWhere + "]";
	}

	/**
	 * 查询条件转换为Json
	 * @return
	 */
	public JSONObject toJson() {

		if (!isLegal()) {
//			LogTool.w("QueryCondition.toJson", "查询条件不合法，无法转换为Json对象");
			return null;
		}

		JSONObject jsObj = new JSONObject();
		try {
			jsObj.put("name", name);
			jsObj.put("qm", qm.toJson());
			jsObj.put("returnAtt", returnAtt);
			jsObj.put("returnGeom", returnGeom);

			JSONArray jsArr = new JSONArray();
			for (String strValue : fldValues) {
				jsArr.put(strValue);
			}

			jsObj.put("fldValues", jsArr);

			jsObj.put("rect", rect.toString());
			jsObj.put("rectName", rectName.getString());

			return jsObj;
		} catch (JSONException e) {
//			LogTool.exception(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 由Json对象解析成查询条件
	 * @param jsObj
	 * @return
	 */
	public static QueryCondition fromJson(JSONObject jsObj) {

		if (jsObj == null) {
			return null;
		}

		QueryCondition qc = new QueryCondition();
		qc.name = jsObj.optString("name");
		
		if(jsObj.has("returnAtt")){
			qc.returnAtt = jsObj.optBoolean("returnAtt");
		}
		if(jsObj.has("returnGeom")){
			qc.returnGeom = jsObj.optBoolean("returnGeom");
		}

		JSONObject jsObjQm = jsObj.optJSONObject("qm");
		JSONArray jsArrFldValues = jsObj.optJSONArray("fldValues");
		String strRect = jsObj.optString("rect");
		String strRectName = jsObj.optString("rectName");

		if (jsObjQm != null && jsArrFldValues != null) {

			QueryModel qm = QueryModel.fromJson(jsObjQm);
			if (qm.size() != jsArrFldValues.length()) {
				return qc;
			}
			qc.qm.setLayer(qm.getLayer());

			for (int index = 0; index < qm.size(); index++) {

				String strFldValue = jsArrFldValues.optString(index);
				qc.fldValues.add(strFldValue);
				qc.qm.add(qm.getFldNames().get(index), qm.getFldRelations().get(index), qm
							.getFldTypes().get(index));
			}
		}

		DRect rect = new DRect(strRect);
		qc.add(rect, EnumRectName.fromString(strRectName));

		return qc;

	}

	/**
	 * 查询类型
	 * @author yangsheng
	 */
	public static enum EnumQueryType {
		/**
		 * 属性查询
		 */
		AttQuery,
		/**
		 * 空间查询
		 */
		SpaceQuery,
		/**
		 * 混合查询
		 */
		MixQuery,
		/**
		 * 未知查询（不合法查询）
		 */
		UnKnown;
	}

	/**
	 * 空间矩形名称
	 * @author yangsheng
	 * @date 2014-9-1
	 */
	public static enum EnumRectName {

		/**
		 * 全图
		 */
		MAP,
		/**
		 * 屏幕
		 */
		SCREEN,
		/**
		 * 空间范围
		 */
		SELECETED,
		/**
		 * 未知
		 */
		UNKNOWN;

		public String getString() {

			String strType = "未知";
			switch (this) {
			case MAP:
				strType = "全图";
				break;
			case SCREEN:
				strType = "屏幕";
				break;

			case SELECETED:
				strType = "空间范围";
				break;

			case UNKNOWN:
				strType = "";
				break;

			default:
				break;
			}

			return strType;
		}

		public static EnumRectName fromString(String strType) {

			if (strType.equalsIgnoreCase("全图")) {
				return MAP;
			} else if (strType.equalsIgnoreCase("屏幕")) {
				return SCREEN;
			} else if (strType.equalsIgnoreCase("空间范围")) {
				return SELECETED;
			} else {
				return UNKNOWN;
			}
		}

		/**
		 * 可选择的名称
		 * @return
		 */
		public static String[] getTypes() {

			String[] arrTypes = new String[2];
			arrTypes[0] = "全图";
			arrTypes[1] = "屏幕";

			return arrTypes;
		}

		/**
		 * 由序号取名称
		 * @param i 0/1/2/3 : 全图/屏幕/空间范围/未知
		 * @return
		 */
		public static EnumRectName fromInt(int i) {

			switch (i) {
			case 0:
				return MAP;
			case 1:
				return SCREEN;
			case 2:
				return SELECETED;
			default:
				return UNKNOWN;
			}
		}
	}

	@Override
	public int describeContents()
	{
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel arg0, int arg1)
	{
		// TODO Auto-generated method stub
		
	}

}
